﻿using DependencyAnalysis.DataModel;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace UnitTests
{
    [TestClass]
    public class DependencyModelTest
    {
        private DependencyModel _dependencyModel;

        [TestInitialize]
        public void Initialize()
        {
            _dependencyModel = new DependencyModel();
            var descriptor = BuildDependencyDescriptor(1, 2, true, false);
            _dependencyModel.Add(descriptor);

            descriptor = BuildDependencyDescriptor(10, 11, true, false);
            descriptor.Target.Identifier = "Module10.Submodule10.Abstract10.Member";
            descriptor.Target.ImplementingType.Identifier = "Module10.Submodule10.Abstract10";
            descriptor.Target.ImplementingType.AbstractionType = AbstractionType.Abstract;
            descriptor.Identifier = "11 @ 10 abstract";
            _dependencyModel.Add(descriptor);
            descriptor = BuildDependencyDescriptor(10, 11, true, false);
            descriptor.Target.Identifier = "Module10.Submodule10.Interface10.Member";
            descriptor.Target.ImplementingType.Identifier = "Module10.Submodule10.Interface10";
            descriptor.Target.ImplementingType.AbstractionType = AbstractionType.Interface;
            descriptor.Identifier = "11 @ 10 interface";
            _dependencyModel.Add(descriptor);
            descriptor = BuildDependencyDescriptor(10, 11, true, false);
            descriptor.Target.Identifier = "Module10.Submodule10.Concrete10.Member";
            descriptor.Target.ImplementingType.Identifier = "Module10.Concrete10.Interface10";
            descriptor.Target.ImplementingType.AbstractionType = AbstractionType.Concrete;
            descriptor.Identifier = "11 @ 10 concrete";
            _dependencyModel.Add(descriptor);
        }

        [TestMethod]
        public void TargetMemberIsAddedToDependecies()
        {
            var descriptor = new MemberDescriptor { Identifier = "Module2.Submodule2.Type2.Member2" };
            Assert.IsTrue(_dependencyModel.DependenciesPerMember.ContainsKey(descriptor));
        }

        [TestMethod]
        public void TargetTypeIsAddedToDependecies()
        {
            var descriptor = new TypeDescriptor { Identifier = "Module2.Submodule2.Type2" };
            Assert.IsTrue(_dependencyModel.DependenciesPerType.ContainsKey(descriptor));
        }

        [TestMethod]
        public void TargetSubmoduleIsAddedToDependecies()
        {
            var descriptor = new SubmoduleDescriptor { Identifier = "Module2.Submodule2" };
            Assert.IsTrue(_dependencyModel.DependenciesPerSubmodule.ContainsKey(descriptor));
        }

        [TestMethod]
        public void TargetModuleIsAddedToDependecies()
        {
            var descriptor = new ModuleDescriptor { Identifier = "Module2" };
            Assert.IsTrue(_dependencyModel.DependenciesPerModule.ContainsKey(descriptor));
        }

        [TestMethod]
        public void SourceMemberIsAddedToDependecies()
        {
            var descriptor = new MemberDescriptor { Identifier = "Module1.Submodule1.Type1.Member1" };
            Assert.IsTrue(_dependencyModel.DependenciesPerMember.ContainsKey(descriptor));
        }

        [TestMethod]
        public void SourceTypeIsAddedToDependecies()
        {
            var descriptor = new TypeDescriptor { Identifier = "Module1.Submodule1.Type1" };
            Assert.IsTrue(_dependencyModel.DependenciesPerType.ContainsKey(descriptor));
        }

        [TestMethod]
        public void SourceSubmoduleIsAddedToDependecies()
        {
            var descriptor = new SubmoduleDescriptor { Identifier = "Module1.Submodule1" };
            Assert.IsTrue(_dependencyModel.DependenciesPerSubmodule.ContainsKey(descriptor));
        }

        [TestMethod]
        public void SourceModuleIsAddedToDependecies()
        {
            var descriptor = new ModuleDescriptor { Identifier = "Module1" };
            Assert.IsTrue(_dependencyModel.DependenciesPerModule.ContainsKey(descriptor));
        }

        [TestMethod]
        public void ForEachAccessDependencyIsAddded()
        {
            var dependencies = _dependencyModel.DependenciesPerModule[new ModuleDescriptor { Identifier = "Module11" }];
            Assert.AreEqual(3, dependencies.Count);
        }

        public static DependencyDescriptor BuildDependencyDescriptor(int sourceNumber, int targetNumber, bool partOfProject1, bool partOfProject2)
        {
            var descriptor = new DependencyDescriptor();
            var module1 = "Module" + sourceNumber;
            var namespace1 = module1 + ".Submodule" + sourceNumber;
            var type1 = namespace1 + ".Type" + sourceNumber;
            var member1 = type1 + ".Member" + sourceNumber;
            var module2 = "Module" + targetNumber;
            var namespace2 = module2 + ".Submodule" + targetNumber;
            var type2 = namespace2 + ".Type" + targetNumber;
            var member2 = type2 + ".Member" + targetNumber;
            descriptor.Source = new MemberDescriptor
                {
                    ImplementingType = new TypeDescriptor
                        {
                            Submodule = new SubmoduleDescriptor
                                {
                                    Module = new ModuleDescriptor
                                        {
                                            FullName = module1,
                                            Identifier = module1,
                                            IsPartOfFramework = false,
                                            IsPartOfProject = partOfProject1
                                        },
                                    FullName = namespace1,
                                    Identifier = namespace1,
                                    Name = "Submodule" + sourceNumber
                                },
                            FullName = type1,
                            Identifier = type1,
                            Name = "Type" + sourceNumber,
                            Visibility = NodeVisibility.Public,
                            AbstractionType = AbstractionType.Concrete
                        },
                    FullName = member1,
                    Identifier = member1,
                    Name = "Member" + sourceNumber,
                    Visibility = NodeVisibility.Public
                };
            descriptor.Source.ImplementingType.Submodule.Module.Submodules.Add(
                descriptor.Source.ImplementingType.Submodule);
            descriptor.Target = new MemberDescriptor
                {
                    ImplementingType = new TypeDescriptor
                        {
                            Submodule = new SubmoduleDescriptor
                                {
                                    Module = new ModuleDescriptor
                                        {
                                            FullName = module2,
                                            Identifier = module2,
                                            IsPartOfFramework = false,
                                            IsPartOfProject = partOfProject2
                                        },
                                    FullName = namespace2,
                                    Identifier = namespace2,
                                    Name = "Submodule" + targetNumber
                                },
                            FullName = type2,
                            Identifier = type2,
                            Name = "Type" + targetNumber,
                            Visibility = NodeVisibility.Public,
                            AbstractionType = AbstractionType.Concrete
                        },
                    FullName = member2,
                    Identifier = member2,
                    Name = "Member" + targetNumber,
                    Visibility = NodeVisibility.Public
                };
            descriptor.Target.ImplementingType.Submodule.Module.Submodules.Add(
                descriptor.Target.ImplementingType.Submodule);
            descriptor.ReferenceType = ReferenceType.AccessMember;
            descriptor.Identifier = descriptor.ReferenceType + "@" + descriptor.Source + "->" + descriptor.Target;
            return descriptor;
        }
    }
}
